package blazingbubble.network.game.strategy;

import blazingbubble.game.Bubble;
import blazingbubble.game.Field;
import blazingbubble.game.Game;
import moltencore.network.protocol.BubbleData;
import moltencore.network.protocol.BubbleNotification;
import spark.network.protocol.Base;

import java.util.Collection;

public class BubbleNotificationStrategy {
	protected Game game;
	private Bubble.State bubbleNature;

	public BubbleNotificationStrategy(Game game, Bubble.State bubbleNature) {
		this.bubbleNature = bubbleNature;
		this.game = game;
	}

	protected Bubble defaultHandle(BubbleNotification packet) {
		Field field = getField(packet);
		Bubble bubble = getBubble(field, packet);

		// if the packets arrived out of order and/or the game field does not know about this bubble yet we spawn it
		if(bubble == null) {
			bubble = makeBubble(packet);
			field.spawnBubble(bubble);
		}

		// we only apply this packets information if the state of this bubble's strategy's nature is a later
		// lifecycle state than the one the bubble is currently in - if not then the packet has arrived out of
		// order and is useless so we don't do anything
		if(getBubbleNature().after(bubble.getState())) {
			handlingHook(field, bubble, packet.getBubbleData());
		}

		return bubble;
	}

	protected void handlingHook(Field field, Bubble bubble, BubbleData bubbleData) {
	}

	protected Field getField(BubbleNotification bubbleNotification) {
		return game.getField(bubbleNotification.getBubbleData().getFieldId());
	}

	protected Bubble getBubble(Field field, BubbleNotification bubbleNotification) {
		return field.getBubble(bubbleNotification.getBubbleData().getBubbleId());
	}

	protected void adjustBubble(Bubble bubble, BubbleData bubbleData) {
		bubble.getWriteLock().lock();
		try {
			bubble.setState(bubbleNature);
			bubble.getPosition().copy(bubbleData.getPosition());
			bubble.getVelocity().copy(bubbleData.getVelocity());
		}
		finally {
			bubble.getWriteLock().unlock();
		}
	}

	protected Bubble makeBubble(BubbleNotification bubbleNotification) {
		BubbleData bubbleData = bubbleNotification.getBubbleData();
		Bubble bubble = new Bubble(bubbleData.getType(), bubbleData.getBubbleId());
		adjustBubble(bubble, bubbleData);
		return bubble;
	}

	protected Bubble.State getBubbleNature() {
		return bubbleNature;
	}
}
